package org.dbstar.scheduler.job.cmd;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.dbstar.scheduler.beans.CmdJob;
import org.dbstar.scheduler.beans.CmdJobResult;
import org.dbstar.scheduler.beans.Job;
import org.dbstar.scheduler.control.JobController;
import org.dbstar.scheduler.job.AbstractJobRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 命令行Job执行器
 * 
 * @author 代波
 * @since 1.0.0
 * @version 1.0.0
 * @date 2012-3-21
 */
public class CmdJobRunner extends AbstractJobRunner {
	private static final Logger LOGGER = LoggerFactory.getLogger(CmdJobRunner.class);
	private static final String lineSeparator = System.getProperty("line.separator");

	public CmdJobRunner(JobController jobController, Job job) {
		super(jobController, job);
	}

	@Override
	protected final boolean run(Job job) throws Exception {
		CmdJobResult result = (CmdJobResult) job.getResult();

		String cmd[] = buildCommand((CmdJob) job);
		Process process;
		if (cmd.length == 1) {
			process = Runtime.getRuntime().exec(cmd[0]);
		} else {
			process = Runtime.getRuntime().exec(cmd);
		}
		Writer wOut = new BufferedWriter(new OutputStreamWriter(result.getStdOutStream()));
		Writer wErr = new BufferedWriter(new OutputStreamWriter(result.getStdErrStream()));
		BufferedReader rOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
		BufferedReader rErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
		startCopyThread(rOut, wOut, "CopyStdOut: " + job.getIdentifier());
		startCopyThread(rErr, wErr, "CopyStdErr: " + job.getIdentifier());
		try {
			result.setExitValue(process.waitFor());
			return true;
		} catch (InterruptedException e) {
			process.destroy();
			return false;
		}
	}

	protected String[] buildCommand(CmdJob job) throws Exception {
		return StringUtils.split(job.getFinalCmd(), '\n');
	}

	private static Thread startCopyThread(final BufferedReader in, final Writer out, final String threadName) {
		Thread copyThread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					String line;
					while ((line = in.readLine()) != null) {
						out.write(System.currentTimeMillis() + "\t" + line + lineSeparator);
						out.flush();
					}
				} catch (Throwable e) {
					LOGGER.error("读取Job结果的错误输出流时发生异常: " + threadName, e);
				} finally {
					IOUtils.closeQuietly(in);
					IOUtils.closeQuietly(out);
				}
			}
		}, threadName);
		copyThread.setDaemon(true);
		copyThread.start();
		return copyThread;
	}
}
